﻿using Chat.Common;
using SuperSocket.ClientEngine;
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace ChatClient
{
    public partial class MainWindow : Form
    {
        private AsyncTcpSession client;

        public MainWindow()
        {
            InitializeComponent();
            CheckForIllegalCrossThreadCalls = false;
        }

        private void bConnect_Click(object sender, EventArgs e)
        {
            if (client != null)
            {
                client.Close();
                client = null;
            }

            if (bConnect.Text == "Disconnect")
            {
                bConnect.Text = "Connect";
                return;
            }

            try
            {
                client = new AsyncTcpSession(new IPEndPoint(IPAddress.Parse(tServer.Text), Convert.ToInt32(tPort.Value)));
                #region // bind events
                client.Closed += client_Closed;
                client.Connected += client_Connected;
                client.DataReceived += client_DataReceived;
                client.Error += client_Error;
                #endregion
                AppendMessage("Connecting...");
                bConnect.Text = "Disconnect";
                client.Connect();
            }
            catch (Exception ex)
            {
                AppendMessage("Connect failed", Environment.NewLine, ex.Message);
            }
        }

        void client_DataReceived(object sender, DataEventArgs e)
        {
            /// 这里要注意：
            /// e.Length 是实际数据的长度
            /// 如果直接使用 Encoding.UTF8.GetString(e.Data) 
            /// 会读取到填充的\0字符，这会引起不可预知的意外
            string data = Encoding.UTF8.GetString(e.Data, 0, e.Length);
            data = Base64.Decode(data);
            ResultStatus rs = JSON.DecodeObject<ResultStatus>(data);

            switch (rs.Type)
            {
                case ResultType.JOIN_RESULT: // 加入结果
                    // 加入成功
                    if (rs.Success)
                    {
                        if (!string.IsNullOrWhiteSpace(rs.Data))
                        {
                            list.Items.Clear();
                            string[] onlineusers = rs.Data.Split(",".ToArray());
                            if (onlineusers != null)
                            {
                                foreach (var item in onlineusers)
                                {
                                    AddUser(item);
                                }
                            }
                        }
                    }
                    else
                    {
                        client.Close();
                        bConnect.Text = "Connect";
                    }

                    AppendMessage(rs.Message);
                    break;
                case ResultType.NEW_JOIN: // 有新用户加入                    
                    AppendMessage(rs.Message);
                    AddUser(rs.Data.ToString());
                    break;
                case ResultType.SEND: // 发送消息结果
                    if (!rs.Success)
                    {
                        AppendMessage(rs.Message);
                    }
                    break;
                case ResultType.RECEIVE: // 收到消息
                    AppendMessage(rs.Message);
                    break;
                case ResultType.QUIT: // 用户退出
                    AppendMessage(rs.Message);
                    RemoveUser(rs.Data.ToString());
                    break;
            }
        }

        void client_Error(object sender, SuperSocket.ClientEngine.ErrorEventArgs e)
        {
            AppendMessage("Error:" + e.Exception.Message);
        }

        void client_Connected(object sender, EventArgs e)
        {
            AppendMessage("Connected. Asking for join...");
            SendText(CMD.JOIN, tName.Text);
        }

        void client_Closed(object sender, EventArgs e)
        {
            AppendMessage("Disconnected.");
            list.Items.Clear();
        }


        string cmdFormat = "{0} {1}\r\n";
        /// <summary>
        /// 向服务器发送命令行协议数据(此函数会将数据以Base64[UTF-8]方式编码，在服务器读取后，需要解码使用)
        /// </summary>
        /// <param name="cmd">请求的命令 </param>
        /// <param name="data">数据</param>
        void SendText(CMD cmd, params string[] data)
        {
            string body = string.Join("", data);
            body = Base64.Encode(body);

            // 完整命令数据
            string cmdData = string.Format(cmdFormat, cmd.ToString(), body);

            // 转换成字节数组
            byte[] byteData = Encoding.UTF8.GetBytes(cmdData);

            client.Send(byteData, 0, byteData.Length);
        }

        void SendBinary(CMD cmd, byte[] data, string toUser = null)
        {
            string header  =string.Format("{0} {1}")
        }

        /// <summary>
        /// 追加日志和历史记录
        /// </summary>
        /// <param name="args"></param>
        private void AppendMessage(params string[] args)
        {
            string msg = "";
            if (args != null)
            {

                foreach (var item in args)
                {
                    msg += item;
                }
                msg += Environment.NewLine;
            }
            tHistory.AppendText(msg);
            tHistory.ScrollToCaret();
        }

        private void bSend_Click(object sender, EventArgs e)
        {

            if (list.Items.Count == 0)
            {
                MessageBox.Show(this, "No user online.");
                return;
            }

            if (tMessage.Controls.Count > 0)
            {
                // 图片
                PictureBox pic = tMessage.Controls[0] as PictureBox;
                Image img = pic.Image;
                tMessage.Controls.Clear();
                Stream s = new MemoryStream();
                img.Save(s, img.RawFormat);

                byte[] data = new byte[s.Length];
                s.Read(data, 0, data.Length);
                s.Close();
                s.Dispose();
                var selected = list.SelectedItems;
                if (selected.Count == 0)
                {
                    SendBinary(CMD.ONE2ALL, data);
                }
                else
                {
                    SendBinary(CMD.ONE2ONE,  data, selected[0].Text);
                }
            }
            else
            {
                string msg = tMessage.Text;

                AppendMessage("[You said]:", msg);
                tMessage.Clear();

                var selected = list.SelectedItems;
                if (selected.Count == 0)
                {
                    SendText(CMD.ONE2ALL, msg);
                }
                else
                {
                    SendText(CMD.ONE2ONE, selected[0].Text, msg);
                }
            }            
        }

        public void AddUser(string name)
        {
            Invoke((MethodInvoker)delegate()
            {
                var row = new ListViewItem(new string[] { name });


                list.Items.Add(row);
            });
        }

        public void RemoveUser(string name)
        {
            Invoke((MethodInvoker)delegate()
            {
                ListViewItem item = null;
                foreach (ListViewItem row in list.Items)
                {
                    if (row.Text == name)
                    {
                        item = row;
                        break;
                    }
                }
                if (item != null)
                {
                    list.Items.Remove(item);
                }
            });
        }

        private void MainWindow_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (client != null)
            {
                if (client.IsConnected)
                {
                    client.Close();
                }
                client = null;
            }
        }

        private void bPic_Click(object sender, EventArgs e)
        {
            if (openFileDialog.ShowDialog(this) == DialogResult.OK)
            {
                LoadPictureData(openFileDialog.FileName);
            }
        }

        private void LoadPictureData(string filename)
        {
            using (FileStream s = new FileStream(filename, FileMode.Open))
            {
                int fileLength = (int)s.Length;

                byte[] data = new byte[fileLength];
                //ArraySegment<byte> seg = new ArraySegment<byte>();
                int segSize = 1024;

                s.Read(data, 0, fileLength);

                Bitmap img = new Bitmap(s);
                InsertPic(img);
            }
        }

        private void InsertPic(string filename)
        {
            InsertPic(new Bitmap(filename));
        }

        private void InsertPic(Bitmap pic)
        {
            PictureBox pb = new PictureBox();
            pb.Width = pic.Width;
            pb.Height = pic.Height;
            pb.Image = pic;

            tMessage.Controls.Add(pb);
        }

        private void MainWindow_Load(object sender, EventArgs e)
        {
            // 图片选择器的初始路径
            openFileDialog.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyPictures);
        }
    }
}
